// i.r(t), i.d(t, { default: () => ee })
import * as THREE from "three"
import { SweepHoverCommand } from "../command/sweep.command"
import { TilingOverrideWindowSizeCommand, TilingSetNavPanoSizeCommand } from "../command/tiling.command"
import { ChangeViewmodeCommand } from "../command/viewmode.command"
import { XRSessionRequestCommand } from "../command/xr.command"
import keyConst from "../constant/key.const"
import CameraData from "../data/CameraData"
import CursorData from "../data/CursorData"
import InteractionmodeData from "../data/InteractionmodeData"
import RaycasterData from "../data/RaycasterData"
import SettingsData from "../data/SettingsData"
import SweepData from "../data/SweepData"
import ViewmodeData from "../data/ViewmodeData"
import modeEnum from "../enum/mode.enum"
import { resolutionMap } from "../enum/resolution.enum"
import TextureLoader from "../loader/TextureLoader"
import a from "../math/19674"
import m from "../math/27687"
import o from "../math/7170"
import F from "../math/82088"
import PuckCollider from "../mesh/PuckCollider"
import TypedMesh from "../mesh/TypedMesh"
import MessageBus from "../message/MessageBus"
import { XRStartPresentingMessage, XRStopPresentingMessage, XRTrackingAppliedMessage } from "../message/xr.message"
import ObservableValue from "../observer/observable.value"
import _ from "../packages/7855"
import SymbolList from "../SymbolList"
import LineSegment from "../three/LineSegment"
import Vectors from "../three/Vectors"
import AggregateSubscription from "../utils/AggregateSubscription"
import browserUtil from "../utils/browser.util"
import Logger from "../utils/Logger"
import RenderLayers from "../utils/RenderLayers"
import { createSubscription, Subscription } from "../utils/Subscription"
import xrUtil from "../utils/xr.util"
import XRControllerModelFactory from "../webxr/XRControllerModelFactory"
import CameraModule from "./CameraModule"
import LinesModule from "./LinesModule"
import Module from "./Module"
import RaycasterModule from "./RaycasterModule"
declare global {
  const XRWebGLLayer: any
}
const w = new THREE.Vector3(0, -100, 0)
const f = new THREE.Vector2(-2, -2)
const v = new THREE.Vector3(-1, -1, -1)
const T = new THREE.Vector3(1, 1, 1)
class RaycastPointerWorld {
  raycaster: any
  lastHits: any[]
  lastRay: THREE.Ray
  currentRay: THREE.Ray
  origin: THREE.Vector3
  direction: THREE.Vector3
  pointerNdc: THREE.Vector2
  cameraCache: { position: THREE.Vector3; quaternion: THREE.Quaternion; camera: any }
  cast: () => any
  update3D: (e: any, t: any, i: any) => void
  updateNDCPosition: () => void
  updatePointer: () => void
  constructor(e) {
    ;(this.raycaster = e),
      (this.lastHits = []),
      (this.lastRay = new THREE.Ray(w, new THREE.Vector3(0, -1, 0))),
      (this.currentRay = new THREE.Ray()),
      (this.origin = w),
      (this.direction = new THREE.Vector3()),
      (this.pointerNdc = f),
      (this.cameraCache = {
        position: new THREE.Vector3(),
        quaternion: new THREE.Quaternion(),
        camera: void 0
      }),
      (this.cast = () => {
        const e = this.currentRay
        return this.lastRay.equals(e) || ((this.lastHits = this.raycaster.cast(e.origin, e.direction).slice()), this.lastRay.copy(e)), this.lastHits
      }),
      (this.update3D = (e, t, i) => {
        e instanceof THREE.Vector3 && this.origin.copy(e),
          t instanceof THREE.Vector3 && this.direction.copy(t),
          (this.cameraCache.camera = i),
          this.currentRay.set(this.origin, this.direction)
      }),
      (this.updateNDCPosition = () => {
        const e = this.lastHits[0]
        if (this.cameraCache.camera && e && e.point) {
          const t = this.cameraCache.camera
          this.cameraCache.position.setFromMatrixPosition(t.matrixWorld), this.cameraCache.quaternion.setFromRotationMatrix(t.matrixWorld)
          const i = m.D_(e.point, this.cameraCache.position, this.cameraCache.quaternion, t.projectionMatrix)
          i.clamp(v, T), this.pointerNdc.set(i.x, i.y)
        }
      }),
      (this.updatePointer = () => {})
  }
  get pointerRay() {
    return this.currentRay
  }
  get ndcPosition() {
    return this.updateNDCPosition(), this.pointerNdc
  }
}

var S = {
  "0": "Mono",
  "1": "Stereo",
  "2": "SixDof",
  "3": "__length",
  Mono: 0,
  Stereo: 1,
  SixDof: 2,
  __length: 3
}

const M = { controllers: Object.freeze([0, 1]), rotationDegrees: 25 }
var x = {
  "0": "touchpadX",
  "1": "touchpadY",
  "2": "thumbstickX",
  "3": "thumbstickY",
  touchpadX: 0,
  touchpadY: 1,
  thumbstickX: 2,
  thumbstickY: 3
}
declare global {
  const XRRigidTransform: any
}
const I = { x: 0, y: 0, z: 0, w: 1 }
class XRTrackingOverrides extends MessageBus {
  engine: any
  renderer: any
  webglScene: any
  cameraData: any
  cameraModule: any
  trackingStyle: any
  session: any
  rotations: { initialYawOffset: THREE.Quaternion; yawOffset: THREE.Quaternion; invYawOffset: THREE.Quaternion; trackingOffset: THREE.Quaternion }
  setTrackingStyle: (e: any) => void
  offsetRotation: (e: any) => void
  onPresentStart: (e: any) => void
  onPresentEnd: () => void
  applyTrackingOverrides: (e: any, t: any, i: any) => void
  frame: any
  constructor(e, t, i, s, n) {
    super(),
      (this.engine = e),
      (this.renderer = t),
      (this.webglScene = i),
      (this.cameraData = s),
      (this.cameraModule = n),
      (this.trackingStyle = S.Mono),
      (this.session = null),
      (this.rotations = {
        initialYawOffset: new THREE.Quaternion(),
        yawOffset: new THREE.Quaternion(),
        invYawOffset: new THREE.Quaternion(),
        trackingOffset: new THREE.Quaternion()
      }),
      (this.setTrackingStyle = e => {
        e < S.__length && ((this.trackingStyle = e), this.resetInitialRotation())
      }),
      (this.offsetRotation = e => {
        this.rotations.invYawOffset.multiply(e), this.rotations.yawOffset.copy(this.rotations.invYawOffset).invert()
      }),
      (this.onPresentStart = e => {
        ;(e.cameras[0].layers.mask = RenderLayers.ALL.mask),
          (e.cameras[1].layers.mask = RenderLayers.ALL.mask),
          (e.cameras[0].far = e.far),
          (e.cameras[1].far = e.far),
          (e.layers.mask = RenderLayers.ALL.mask),
          this.resetInitialRotation(),
          this.broadcast(new XRStartPresentingMessage())
      }),
      (this.resetInitialRotation = () => {
        const e = this.cameraData.pose.rotation.clone()
        a.Rq(e, this.rotations.initialYawOffset),
          this.rotations.yawOffset.copy(this.rotations.initialYawOffset),
          this.rotations.invYawOffset.copy(this.rotations.initialYawOffset).invert()
      }),
      (this.onPresentEnd = () => {
        this.broadcast(new XRStopPresentingMessage())
      }),
      (this.applyTrackingOverrides = (e, t, i) => {
        if (e.xr.isPresenting && i instanceof THREE.ArrayCamera) {
          e.clear()
          const t = i.cameras[0],
            s = i.cameras[1]
          if (
            ((this.frame = this.engine.getXrFrame()), this.session || ((this.session = e.xr.getSession()), this.onPresentStart(i)), this.frame && this.session)
          ) {
            this.rotations.trackingOffset.copy(this.rotations.yawOffset).multiply(i.quaternion),
              this.cameraModule.updateCameraRotation(this.rotations.trackingOffset)
            const e = this.webglScene.camera.parent
            if (e) {
              const t = this.getReferenceSpace(this.frame, e)
              this.updateCameras(i, this.frame, t, e), this.updateControllers(this.session, this.frame, t, e)
            }
            switch (this.trackingStyle) {
              case S.Mono:
                s.matrixWorld.copy(t.matrixWorld), s.matrixWorldInverse.copy(s.matrixWorld), s.matrixWorldInverse.invert()
            }
            this.broadcast(new XRTrackingAppliedMessage(t))
          }
        } else this.session && ((this.session = null), this.onPresentEnd())
      }),
      (this.getReferenceSpace = (e, t) => {
        const i = this.renderer.xr.getReferenceSpace(),
          s = e.getViewerPose(i).views[0].transform.position,
          n = this.trackingStyle === S.SixDof ? I : s,
          r = new XRRigidTransform({
            x: n.x - t.position.x,
            y: n.y - t.position.y,
            z: n.z - t.position.z
          }),
          o = i.getOffsetReferenceSpace(r),
          a = this.rotations.invYawOffset,
          h = this.cameraData.pose.position,
          l = new XRRigidTransform({ x: h.x, y: h.y, z: h.z, w: 1 }, { x: a.x, y: a.y, z: a.z, w: a.w })
        return o.getOffsetReferenceSpace(l)
      }),
      (this.updateCameras = (e, t, i, s) => {
        const n = t.getViewerPose(i)
        if (n) {
          const t = n.views
          for (let i = 0; i < t.length; i++) {
            const n = t[i],
              r = e.cameras[i]
            r.matrix.fromArray(n.transform.matrix),
              r.projectionMatrix.fromArray(n.projectionMatrix),
              r.projectionMatrixInverse.copy(r.projectionMatrix),
              r.projectionMatrixInverse.invert(),
              r.matrixWorld.multiplyMatrices(s.matrixWorld, r.matrix),
              r.matrixWorldInverse.copy(r.matrixWorld),
              r.matrixWorldInverse.invert(),
              r.matrix.decompose(r.position, r.quaternion, r.scale),
              0 === i &&
                (e.matrix.copy(r.matrix),
                e.matrix.decompose(e.position, e.quaternion, e.scale),
                e.matrixWorld.copy(r.matrixWorld),
                e.matrixWorldInverse.copy(r.matrixWorldInverse),
                e.projectionMatrix.copy(r.projectionMatrix),
                e.projectionMatrixInverse.copy(r.projectionMatrixInverse))
          }
        }
      }),
      (this.updateControllers = (e, t, i, s) => {
        for (let n = 0; n < 2; n++) {
          const r = this.renderer.xr.getController(n),
            o = this.renderer.xr.getControllerGrip(n),
            a = e.inputSources[n]
          let h = null,
            l = null
          a &&
            (r &&
              ((h = t.getPose(a.targetRaySpace, i)),
              h &&
                (r.matrix.fromArray(h.transform.matrix),
                r.matrixWorld.multiplyMatrices(s.matrixWorld, r.matrix),
                r.matrix.decompose(r.position, r.quaternion, r.scale)),
              (r.visible = !!h)),
            o &&
              a.gripSpace &&
              ((l = t.getPose(a.gripSpace, i)),
              l &&
                (o.matrix.fromArray(l.transform.matrix),
                o.matrixWorld.multiplyMatrices(s.matrixWorld, o.matrix),
                o.children.forEach(e => {
                  e.updateMatrixWorld()
                }),
                o.matrix.decompose(o.position, o.quaternion, o.scale)))),
            o && (o.visible = !!l)
        }
      }),
      (this.webglScene.scene.onBeforeRender = this.applyTrackingOverrides)
  }
  resetInitialRotation: any
  getReferenceSpace: any
  updateCameras: any
  updateControllers: any
}
class XRNavigationVisuals {
  active: boolean
  target: ObservableValue<any>
  previousSweep: any
  activate: () => void
  updateLoopSub: any
  selectionChangeSub: any
  ray: any
  targetDecoration: any
  deactivate: () => void
  getTargetSweep: (e: any, t: any, i: any) => any
  _container: any
  engine: any
  constructor() {
    ;(this.active = !1),
      (this.target = new ObservableValue(null)),
      (this.previousSweep = null),
      (this.activate = () => {
        this.active || (this.updateLoopSub.renew(), this.selectionChangeSub.renew(), this.ray.toggle(!0), this.targetDecoration.toggle(!0), (this.active = !0))
      }),
      (this.deactivate = () => {
        this.active &&
          ((this.target.value = null),
          this.selectionChangeSub.cancel(),
          this.updateLoopSub.cancel(),
          this.ray.toggle(!1),
          this.targetDecoration.toggle(!1),
          (this.active = !1))
      }),
      (this.getTargetSweep = (e, t, i) => {
        let s = null
        if (t.object instanceof PuckCollider) return (s = e.getSweep(t.object.userData.sid)), s
        const n = F.bG(e, !0, t.intersection)
        return (s = n.length > 0 ? n[0].sweep : null), s
      })
  }
  get container() {
    return this._container
  }
  async init(e) {
    ;(this.engine = e),
      (this._container = new THREE.Group()),
      (this._container.name = "XRNavigationVisuals"),
      (this.ray = new XRTargetRay(this.container)),
      (this.targetDecoration = new XRTargetDecoration(this.container))
    const t = await this.engine.market.waitForData(RaycasterData)
    return (
      (this.updateLoopSub = t.onChanged(() => this.update(t))),
      this.updateLoopSub.cancel(),
      (this.selectionChangeSub = this.target.onChanged(e => {
        null !== this.previousSweep && this.engine.commandBinder.issueCommand(new SweepHoverCommand(this.previousSweep.id, !1, 200)),
          null !== e &&
            (this.engine.commandBinder.issueCommand(new SweepHoverCommand(e.id, !0, 200)), this.targetDecoration.updateTargetPosition(e.floorPosition)),
          (this.previousSweep = e)
      })),
      this.selectionChangeSub.cancel(),
      this
    )
  }
  update(e) {
    const t = this.engine.market.tryGetData(SweepData),
      i = this.engine.market.tryGetData(CameraData),
      s = this.engine.market.tryGetData(ViewmodeData),
      n = this.engine.market.tryGetData(CursorData),
      r = this.engine.market.tryGetData(InteractionmodeData)
    if (!(t && i && s && r && n)) return
    if (!r.isVR()) return
    if (!s.isInside()) return
    const { hit: o, pointerDirection: a, pointerOrigin: h } = e
    if (!o) return
    const l = this.getTargetSweep(t, o, a)
    ;(this.target.value = l), this.ray.update(h, o.point, n.opacity.value), this.targetDecoration.update(i.pose.rotation, n.opacity.value)
  }
}
class XRTargetRay {
  container: any
  styles: {
    ray: { color: string; transparent: boolean; opacity: number; linewidth: number; depthWrite: boolean }
    hit: { color: string; transparent: boolean; opacity: number }
    hitScale: number
  }
  update: (e: any, t: any, i: any) => void
  ray: any
  hitMarker: any
  toggle: (e: any) => void
  constructor(e) {
    ;(this.container = e),
      (this.styles = {
        ray: {
          color: "white",
          transparent: !0,
          opacity: 0.3,
          linewidth: 2,
          depthWrite: !1
        },
        hit: { color: "white", transparent: !0, opacity: 0.3 },
        hitScale: 0.02
      }),
      (this.update = (e, t, i) => {
        this.ray.updatePositions(e, t).opacity(Math.min(i, this.styles.ray.opacity)),
          this.hitMarker.position.copy(t),
          (this.hitMarker.material.opacity = Math.min(i, this.styles.hit.opacity))
      }),
      (this.toggle = e => {
        e
          ? (this.container.add(...this.ray.children), this.container.add(this.hitMarker))
          : (this.container.remove(...this.ray.children), this.container.remove(this.hitMarker))
      })
    const { ray: t, hit: i } = this.styles,
      s = LinesModule.makeLineMaterial(t.color, !1, t)
    ;(this.ray = new LineSegment(new THREE.Vector3(), new THREE.Vector3(), s, {})),
      this.ray.updateResolution(window.innerWidth, window.innerHeight),
      (this.hitMarker = new TypedMesh(new THREE.SphereBufferGeometry(this.styles.hitScale), new THREE.MeshBasicMaterial(i))),
      (this.hitMarker.name = "hit")
  }
}
class XRTargetDecoration {
  container: any
  styles: {
    scale: number
    animationSpeed: number
    plane: { color: string; transparent: boolean; opacity: number; depthWrite: boolean; depthTest: boolean; map: THREE.Texture }
  }
  position: THREE.Vector3
  quaternion: THREE.Quaternion
  updateTargetPosition: (e: any) => void
  update: (e: any, t: any) => void
  target: any
  toggle: (e: any) => void
  constructor(e) {
    ;(this.container = e),
      (this.styles = {
        scale: 0.46,
        animationSpeed: 1,
        plane: {
          color: "white",
          transparent: !0,
          opacity: 0.6,
          depthWrite: !1,
          depthTest: !1,
          map: TextureLoader("./images/selected_sweep_glow.png")
        }
      }),
      (this.position = new THREE.Vector3()),
      (this.quaternion = new THREE.Quaternion()),
      (this.updateTargetPosition = e => {
        this.position.copy(a.Xv(e, Vectors.UP, 0.05))
      }),
      (this.update = (e, t) => {
        const i = a.Rq(e, this.quaternion)
        this.target.quaternion.copy(i),
          this.target.position.lerp(this.position, this.styles.animationSpeed),
          (this.target.material.opacity = Math.min(t, this.styles.plane.opacity))
      }),
      (this.toggle = e => {
        e ? this.container.add(this.target) : this.container.remove(this.target)
      })
    const t = new THREE.PlaneBufferGeometry(1),
      i = new THREE.Matrix4()
    i.makeRotationFromEuler(new THREE.Euler(-Math.PI / 2, 0, 0, "XYZ")),
      t.applyMatrix4(i),
      (this.target = new TypedMesh(t, new THREE.MeshBasicMaterial(this.styles.plane))),
      (this.target.name = "Destination"),
      this.target.scale.set(this.styles.scale, this.styles.scale, this.styles.scale)
  }
}
class XRControllerFocus {
  controllers: any
  _lastInputWas: number
  constructor(e) {
    ;(this.controllers = e), (this._lastInputWas = 0)
  }
  focus(e) {
    e !== this._lastInputWas &&
      (M.controllers.forEach(t => {
        this.controllers.controller(t).grip.visible = t !== e
      }),
      (this._lastInputWas = e))
  }
}
class XRControllerMesh {
  renderer: any
  _defaultController: number
  controllerGroups: any[]
  bindings: any[]
  cancel: () => void
  container: THREE.Group
  constructor(e) {
    ;(this.renderer = e),
      (this._defaultController = 0),
      (this.controllerGroups = []),
      (this.bindings = []),
      (this.cancel = () => {
        this.bindings.forEach(e => e.cancel()), (this.bindings.length = 0)
      }),
      (this.container = new THREE.Group()),
      (this.container.name = "XRControllerMesh"),
      M.controllers.forEach(e => {
        const t = this.createControllerGroup(e)
        this.controllerGroups.push(t), this.container.add(t.grip, t.pointer)
      }),
      this.connectControllerModel(),
      (this.container.matrixAutoUpdate = !1)
  }
  controller(e = this._defaultController) {
    return this.controllerGroups[e]
  }
  setDefault(e) {
    this._defaultController = e
  }
  async connectControllerModel() {
    const e = new XRControllerModelFactory()
    M.controllers.forEach(t => {
      const i = this.controller(t).grip
      i.add(e.createControllerModel(i))
    })
  }
  createControllerGroup(e) {
    const t = this.renderer.xr.getController(e)
    t.name = `Controller Ray ${e}`
    const i = this.renderer.xr.getControllerGrip(e)
    ;(i.name = `Controller Grip ${e}`), (i.visible = !1)
    const s = {
        index: e,
        pointer: t,
        grip: i,
        connected: !1,
        hand: "none"
      },
      n = e => {
        ;(s.hand = e.data.handedness), (s.connected = !0)
      },
      r = () => {
        ;(s.hand = "none"), (s.connected = !1)
      }
    return (
      this.bindings.push(
        createSubscription(
          () => t.addEventListener("connected", n),
          () => t.removeEventListener("connected", n)
        ),
        createSubscription(
          () => t.addEventListener("disconnected", r),
          () => t.removeEventListener("disconnected", r)
        )
      ),
      s
    )
  }
}
const Q = new Logger("xr-input-forwarding")
class XRControllerPointerEventAdapter {
  options: any
  dispatchPointerDown: (e: any) => void
  dispatchPointerUp: (e: any) => void
  target: any
  constructor(e) {
    ;(this.options = e),
      (this.dispatchPointerDown = e => {
        this.forwardEvent("pointerdown", this.mockPointerEventInit(e))
      }),
      (this.dispatchPointerUp = e => {
        this.forwardEvent("pointerup", this.mockPointerEventInit(e))
      }),
      (this.target = e.forwardToElement)
  }
  dispatchPointerMove(e) {
    this.forwardEvent("pointermove", this.mockPointerEventInit(e))
  }
  mockPointerEventInit(e) {
    let t = 0,
      i = 0
    if (this.options.getPointerScreenPosition) {
      const e = this.options.getPointerScreenPosition()
      ;(t = e.x), (i = e.y)
    }
    return {
      pointerType: "gamepad",
      pointerId: e,
      clientX: t,
      clientY: i
    }
  }
  forwardEvent(e, t) {
    let i
    try {
      ;(i = window.PointerEvent ? new PointerEvent(e, t) : new MouseEvent(e, t)), i && this.target.dispatchEvent(i)
    } catch (e) {
      Q.error(e)
    }
  }
}
class XRGamepadInput extends THREE.EventDispatcher {
  renderer: any
  options: { forwardNativeXrEvents: boolean; dispatchToControllerGroup: boolean; axisMoveTriggerThreshold: number }
  previousGamepad: Map<any, any>
  forwardedEvents: string[]
  active: boolean
  renew: () => void
  cancel: () => void
  updateFromGamepads: () => void
  onGamepadEvent: (e: any, t: any) => Subscription
  onSessionEvent: (e: any, t: any) => Subscription
  sendSessionEvent: (e: any, t: any) => void
  constructor(e, t?) {
    super(),
      (this.renderer = e),
      (this.options = {
        forwardNativeXrEvents: !0,
        dispatchToControllerGroup: !1,
        axisMoveTriggerThreshold: 0.5
      }),
      (this.previousGamepad = new Map()),
      (this.forwardedEvents = ["selectstart", "select", "selectend", "squeeze", "squeezestart", "squeezeend"]),
      (this.active = !1),
      (this.renew = () => {
        !this.active && this.options.forwardNativeXrEvents && (this.addSessionListeners(), (this.active = !0))
      }),
      (this.cancel = () => {
        this.active && this.options.forwardNativeXrEvents && (this.removeSessionListeners(), (this.active = !1))
      }),
      (this.updateFromGamepads = () => {
        if (!this.active) return
        const e = this.renderer.xr.getSession()
        if (e)
          for (const t of M.controllers) {
            const i = e.inputSources[t]
            if (!i || !i.gamepad) continue
            const s = this.renderer.xr.getController(t),
              n = this.previousGamepad.get(i),
              r = {
                buttons: i.gamepad.buttons.map(e => e.value),
                axes: i.gamepad.axes.slice()
              },
              o = { controllerIndex: t, inputSource: i, axes: r.axes }
            n &&
              (r.buttons.forEach((e, t) => {
                e !== n.buttons[t] &&
                  (1 === e
                    ? this.sendGamepadEvent(
                        s,
                        Object.assign(Object.assign({}, o), {
                          type: "buttondown",
                          value: e,
                          index: t
                        })
                      )
                    : 0 === e &&
                      this.sendGamepadEvent(
                        s,
                        Object.assign(Object.assign({}, o), {
                          type: "buttonup",
                          value: e,
                          index: t
                        })
                      ))
              }),
              r.axes.forEach((e, t) => {
                const i = n.axes[t]
                if (e !== i) {
                  this.sendGamepadEvent(
                    s,
                    Object.assign(Object.assign({}, o), {
                      type: "axesmove",
                      value: e,
                      index: t
                    })
                  ),
                    0 === i &&
                      this.sendGamepadEvent(
                        s,
                        Object.assign(Object.assign({}, o), {
                          type: "axesmovestart",
                          value: e,
                          index: t
                        })
                      )
                  const n = this.options.axisMoveTriggerThreshold
                  Math.abs(i) < n &&
                    Math.abs(e) > n &&
                    this.sendGamepadEvent(
                      s,
                      Object.assign(Object.assign({}, o), {
                        type: "axestriggered",
                        value: e,
                        index: t
                      })
                    ),
                    0 === e &&
                      this.sendGamepadEvent(
                        s,
                        Object.assign(Object.assign({}, o), {
                          type: "axesmoveend",
                          value: e,
                          index: t
                        })
                      )
                }
              })),
              this.previousGamepad.set(i, r)
          }
      }),
      (this.onGamepadEvent = (e, t) =>
        createSubscription(
          () => super.addEventListener(e, t),
          () => super.removeEventListener(e, t)
        )),
      (this.onSessionEvent = (e, t) =>
        createSubscription(
          () => super.addEventListener(e, t),
          () => super.removeEventListener(e, t)
        )),
      (this.sendGamepadEvent = (e, t) => {
        this.dispatchEvent(t), this.options.dispatchToControllerGroup && e.dispatchEvent(t)
      }),
      (this.sendSessionEvent = (e, t) => {
        this.dispatchEvent({ type: e, controllerIndex: t })
      }),
      (this.addSessionListeners = () => {
        M.controllers.forEach(e => {
          const t = this.renderer.xr.getController(e)
          for (const i of this.forwardedEvents) t.addEventListener(i, t => this.sendSessionEvent(t.type, e))
        })
      }),
      (this.removeSessionListeners = () => {
        M.controllers.forEach(e => {
          const t = this.renderer.xr.getController(e)
          for (const i of this.forwardedEvents) t.removeEventListener(i, t => this.sendSessionEvent(t.type, e))
        })
      }),
      t && (this.options = Object.assign(Object.assign({}, this.options), t)),
      this.renew()
  }
  addSessionListeners: any
  removeSessionListeners: any
  sendGamepadEvent: any
}
const $ = new Logger("xr"),
  K = new THREE.Quaternion().setFromAxisAngle(Vectors.UP, o.Ue * M.rotationDegrees),
  J = new THREE.Quaternion().setFromAxisAngle(Vectors.UP, o.Ue * -M.rotationDegrees)
export default class WebXRModule extends Module {
  framebufferScaledTo: number
  framebufferScale: number
  ray: { forward: THREE.Vector3; origin: THREE.Vector3 }
  onXrPresentBegin: () => void
  renderer: any
  engine: any
  viewmodeData: any
  xrPointer: RaycastPointerWorld
  raycaster: any
  xrNavVisuals: any
  onXrPresentEnd: () => void
  settings: any
  config: any
  cameraModule: any
  cameraData: any
  webglScene: any
  onXrTrackingApplied: (e: any) => void
  controllerMesh: any
  xrPointerInput: any
  xrGamepadInput: any
  requestSession: (e: any, t: any) => Promise<any>
  canvasModule: any
  raycasterData: any
  constructor() {
    super(...arguments),
      (this.name = "webxr"),
      (this.framebufferScaledTo = 1),
      (this.framebufferScale = 0),
      (this.ray = { forward: new THREE.Vector3(), origin: new THREE.Vector3() }),
      (this.onXrPresentBegin = () => {
        const e = this.renderer.xr.getSession()
        $.info(`Session framebuffer: ${e.renderState.baseLayer}`),
          this.engine.commandBinder.issueCommand(new TilingOverrideWindowSizeCommand(!0)),
          this.engine.commandBinder.issueCommand(new TilingSetNavPanoSizeCommand(resolutionMap.HIGH)),
          this.viewmodeData.isInside() || this.engine.commandBinder.issueCommand(new ChangeViewmodeCommand(modeEnum.INSIDE)),
          (this.xrPointer = new RaycastPointerWorld(this.raycaster.picking)),
          this.raycaster.setOverridePointer(this.xrPointer),
          this.xrNavVisuals.activate()
      }),
      (this.onXrPresentEnd = () => {
        const e = null !== this.settings.tryGetProperty(keyConst.settings.tiling.quality, null)
        this.engine.commandBinder.issueCommand(new TilingOverrideWindowSizeCommand(e)),
          this.engine.commandBinder.issueCommand(new TilingSetNavPanoSizeCommand(this.config.navPanoSize)),
          this.xrNavVisuals.deactivate(),
          this.raycaster.setOverridePointer(null),
          this.cameraModule.updateCameraRotation(a.Rq(this.cameraData.pose.rotation, new THREE.Quaternion())),
          this.webglScene.setCameraDirty()
      }),
      (this.onXrTrackingApplied = e => {
        const t = this.controllerMesh.controller()
        if (t.connected) {
          const i = this.ray.forward.copy(Vectors.FORWARD).applyQuaternion(t.pointer.quaternion),
            s = this.ray.origin.setFromMatrixPosition(t.pointer.matrixWorld)
          this.xrPointer.update3D(s, i, e.trackedCamera), this.xrPointerInput.dispatchPointerMove(t.index)
        }
        this.xrGamepadInput.updateFromGamepads()
      }),
      (this.requestSession = async (e, t) => {
        if ((await _.pl()) !== _.bk.webxr) return null
        if (this.renderer.xr.isPresenting) return this.renderer.xr.getSession()
        if (xrUtil.apiExists()) {
          const i = await navigator["xr"].requestSession(e, {
              optionalFeatures: t
            }),
            s = XRWebGLLayer.getNativeFramebufferScaleFactor(i)
          return (
            (this.framebufferScaledTo = this.framebufferScale * (s - 1) + 1),
            $.info("Scaling framebuffer by:", this.framebufferScaledTo, "native size:", s, " * factor:", this.framebufferScale),
            0 !== this.framebufferScale && this.renderer.xr.setFramebufferScaleFactor(this.framebufferScaledTo),
            this.renderer.xr.setSession(i),
            i
          )
        }
        return null
      })
  }
  async init(e, t) {
    ;(this.config = e), (this.engine = t)
    const i = await t.getModuleBySymbol(SymbolList.WEBGL_RENDERER)
    ;(this.renderer = i.threeRenderer),
      (this.webglScene = i.getScene()),
      (this.settings = await t.market.waitForData(SettingsData)),
      this.bindings.push(t.commandBinder.addBinding(XRSessionRequestCommand, e => this.requestSession(e.type, e.features)))
    if ((await _.pl()) !== _.bk.webxr) return
    ;([this.canvasModule, this.cameraModule, this.raycaster] = await Promise.all([
      t.getModuleBySymbol(SymbolList.CANVAS),
      t.getModule(CameraModule),
      t.getModule(RaycasterModule)
    ])),
      ([this.cameraData, this.raycasterData, this.viewmodeData] = await Promise.all([
        t.market.waitForData(CameraData),
        t.market.waitForData(RaycasterData),
        t.market.waitForData(ViewmodeData)
      ])),
      this.renderer.xr.setReferenceSpaceType("local"),
      (this.framebufferScale =
        this.config.framebufferScaling ||
        (function (e) {
          const t = browserUtil.isMobile()
          return !t ||
            (t &&
              (function (e) {
                return /Adreno \(TM\) (540|[6-9]\d\d)/.test(e.renderer)
              })(e))
            ? 1
            : 0
        })(i.gpuInfo))
    const s = new XRTrackingOverrides(t, this.renderer, this.webglScene, this.cameraData, this.cameraModule)
    s.setTrackingStyle(e.tracking),
      this.bindings.push(
        s.subscribe(XRStartPresentingMessage, this.onXrPresentBegin),
        s.subscribe(XRStopPresentingMessage, this.onXrPresentEnd),
        s.subscribe(XRTrackingAppliedMessage, this.onXrTrackingApplied)
      ),
      (this.controllerMesh = new XRControllerMesh(this.renderer)),
      this.webglScene.add(this.controllerMesh.container)
    const n = new XRControllerFocus(this.controllerMesh),
      o = e.enableEventPositions ? () => this.raycasterData.pointerScreenPosition : void 0
    ;(this.xrPointerInput = new XRControllerPointerEventAdapter({
      forwardToElement: this.canvasModule.element,
      getPointerScreenPosition: o
    })),
      (this.xrGamepadInput = new XRGamepadInput(this.renderer))
    const a = new AggregateSubscription(
      this.xrGamepadInput.onGamepadEvent("axestriggered", e => {
        if (e.index === x.thumbstickX || e.index === x.touchpadX) {
          $.debug(`${e.inputSource.handedness} ${x[e.index]} axis.value over threshold, do the rotate!`)
          Math.sign(e.value) > 0 ? s.offsetRotation(K) : s.offsetRotation(J)
        }
        n.focus(e.controllerIndex), this.controllerMesh.setDefault(e.controllerIndex)
      }),
      this.xrGamepadInput.onSessionEvent("selectstart", e => {
        this.xrPointerInput.dispatchPointerDown(e.controllerIndex), n.focus(e.controllerIndex), this.controllerMesh.setDefault(e.controllerIndex)
      }),
      this.xrGamepadInput.onSessionEvent("selectend", e => {
        this.xrPointerInput.dispatchPointerUp(e.controllerIndex), n.focus(e.controllerIndex), this.controllerMesh.setDefault(e.controllerIndex)
      }),
      this.xrGamepadInput.onSessionEvent("squeezestart", e => {
        n.focus(e.controllerIndex), this.controllerMesh.setDefault(e.controllerIndex)
      })
    )
    this.bindings.push(a, this.xrGamepadInput),
      (this.xrNavVisuals = new XRNavigationVisuals()),
      this.xrNavVisuals.init(t),
      this.webglScene.add(this.xrNavVisuals.container)
  }
}
